package com.iflytek.ci.qams.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.validation.Valid;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.iflytek.ci.common.service.AttachmentService;
import com.iflytek.ci.cpms.domain.Project;
import com.iflytek.ci.cpms.service.ProjectService;
import com.iflytek.ci.cums.domain.Account;
import com.iflytek.framework.web.messages.AjaxMessage;
import com.iflytek.ci.cums.service.AccountService;
import com.iflytek.ci.cums.service.impl.ShiroDbRealm;
import com.iflytek.ci.main.controller.BaseController;
import com.iflytek.ci.main.domain.Attachment;
import com.iflytek.ci.main.dto.CommboValue;
import com.iflytek.ci.main.dto.Macro;
import com.iflytek.ci.main.dto.Prior;
import com.iflytek.ci.main.utils.Dates;
import com.iflytek.ci.qams.domain.Comment;
import com.iflytek.ci.qams.domain.Issue;
import com.iflytek.ci.qams.domain.IssueInformation;
import com.iflytek.ci.qams.domain.Priopity;
import com.iflytek.ci.qams.dto.CommentAction;
import com.iflytek.ci.qams.service.CommentService;
import com.iflytek.ci.qams.service.IssueService;
import com.iflytek.ci.qams.service.LabelService;
import com.iflytek.ci.qams.service.PriopityService;
import com.iflytek.ci.qams.service.TypeService;
import com.iflytek.framework.mapper.JsonMapper;
import com.iflytek.framework.pagination.PaginationCriteria;
import com.iflytek.framework.pagination.PaginationResult;
import com.iflytek.framework.web.mvc.PaginationParam;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

/**
 * <p>
 * 反馈信息维护管理控制器.
 * </p>
 *
 * @author xzyan
 * @version 1.0 12-11-2 下午2:59
 * @since JDK 1.5
 */
@Controller
@RequestMapping("/issue/**")
public class IssueController extends BaseController {

	/** 序列化ID */
	private static final long serialVersionUID = -4855119072644142204L;
	/** 反馈问题服务 */
	@Autowired
	private IssueService issueService;
	/** 映射 */
	@Autowired
	private Mapper mapper;
	/** 项目服务 */
	@Autowired
	private ProjectService projectService;
	/** 类型服务 */
	@Autowired
	private TypeService typeService;
	/** 附件服务 */
	@Autowired
	private AttachmentService attachmentService;
	/** 回复问题服务 */
	@Autowired
	private CommentService commentService;
	/** 标签服务 */
	@Autowired
	private LabelService labelService;
	/** 优先级服务 */
	@Autowired
	private PriopityService priopityService;
	/** 获取登录用户 */
	@Autowired
	private AccountService accountService;

	/**
	 * 进入显示页面
	 *
	 * @return 显示页面地址
	 */
	@RequestMapping(value = "list", method = RequestMethod.GET)
	public String list(final Model model) {
		model.addAttribute("type_json",
				JsonMapper.nonDefaultMapper().toJson(typeService.all_types()));
		model.addAttribute("labels", labelService.all_labels());
		final List<Priopity> priopity_list = priopityService.priopity();
		model.addAttribute("priopities", priopity_list);
		model.addAttribute("priopities_json", JsonMapper.nonDefaultMapper()
				.toJson(priopity_list));
		return "issue/list";
	}

	/**
	 * 分页获取反馈信息
	 *
	 * @param criteria 分页参数信息
	 * @param label    tab标签：可能值有todo（待处理） done（已处理） all（所有）（这前三者为
	 *                 指派给我的+我负责的，第四个为我提出的） my_issue (我的反馈)
	 * @param b_assign toolbar 右按钮:可能值有:all_my_issue assign_to_me （指派给我的反馈）
	 * @param fix      问题修复开关，可能值有：fixed （已修复 待处理） f_all（所有待处理 ） null
	 * @return 反馈信息
	 */
	@RequestMapping("list.json")
	@ResponseBody
	public PaginationResult<Issue> all_issues(
			@PaginationParam(required = false) PaginationCriteria criteria,
			@RequestParam(value = "label", required = false) String label,
			@RequestParam(value = "b_assign", required = false) String b_assign,
			@RequestParam(value = "fix", required = false) String fix) {
		ShiroDbRealm.ShiroUser shiro = (ShiroDbRealm.ShiroUser) SecurityUtils
				.getSubject().getPrincipal();
		// 对应tab标签为：我的反馈时
		if (StringUtils.equals(label, "my_issue")) {
			logger.info("my_issue");
			return issueService.page_reporte_status(criteria, shiro.getLogin());
		}
		// 对应button为: fix 时
		if (StringUtils.equals(fix, "fixed")) {
			return issueService.page_issue_fixed(criteria);
		} else if (StringUtils.equals(fix, "f_all")) {
			final Map<String, Object> params = Maps.newHashMap();
			params.put("label", "todo");
			return issueService.find_issues(criteria, params);
		}
		if (StringUtils.equals(b_assign, "all_my_issue")) {
			logger.info("all_my_issue");
			if (StringUtils.equals(label, "all")) {
				// 查询所有反馈
				return issueService.get_all_issues(criteria);
			} else {
				// 设定Label，并进行查询
				final Map<String, Object> params = Maps.newHashMap();
				params.put("label", label);
				return issueService.find_issues(criteria, params);
			}
		} else {
			// 查询指派给我的 assign_to_me （同时要符合label）
			return issueService.page_assignee_status(shiro.getLogin(), label,
					criteria);
		}
	}

	/**
	 * 添加问题反馈
	 * <p/>
	 * 返回添加问题视图
	 */
	@RequestMapping(value = "add", method = RequestMethod.GET)
	public String add_issue(Model model) {
		model.addAttribute("types", typeService.all_types());
		ShiroDbRealm.ShiroUser current_login_usr = (ShiroDbRealm.ShiroUser) SecurityUtils
				.getSubject().getPrincipal();
		// 从数据库中获取当前用户的信息
		final Account account = accountService
				.fromId(current_login_usr.getId());
		model.addAttribute("account", account);
		logger.info(account.getMail());

		return "issue/add";
	}

	/**
	 * <p>
	 * Show assign view 1.
	 * </p>
	 *
	 * @param p_ids map
	 * @return assign view
	 */
	@RequestMapping(value = "assign")
	@ResponseBody
	public List<Map<String, Object>> assign_view(String p_ids) {
		List<Map<String, Object>> params = Lists.newArrayList();
		String[] pids = p_ids.split(Prior.SEPARATE);
		List<String> temp_pid_list = Lists.newArrayList();
		for (String item : pids) {
			if (!temp_pid_list.contains(item)) {
				temp_pid_list.add(item);
				List<Account> accounts = issueService.uinfo(item);
				Map<String, Object> info = new HashMap<String, Object>();
				info.put("project_id", item);
				info.put("project_name",
						projectService.fromId(Integer.valueOf(item)).getName());
				info.put("project_team", accounts);
				params.add(info);
			}
		}
		return params;

	}

	/**
	 * get assign for an issue method get
	 *
	 * @return accounts
	 */
	@RequestMapping(value = "view_assign/{pid}", method = RequestMethod.GET)
	@ResponseBody
	public List<Account> view_accounts(@PathVariable String pid) {
		return issueService.uinfo(pid);
	}

	@RequestMapping(value = "view_assign_submit")
	@ResponseBody
	public AjaxMessage view_assign_submit(String id, String name) {
		String[] ids = id.split(Prior.SEPARATE);
		issueService.update_assignee(ids, name);
		return ajax_info("OK");
	}

	/**
	 * @param ids paramString
	 * @return ajax_info
	 */
	@RequestMapping(value = "assign_submit")
	@ResponseBody
	public AjaxMessage Submit_Assign(String ids, String names) {
		String[] ids_list = ids.split(Prior.SEPARATE);
		String[] names_list = names.split(Prior.SEPARATE);
		for (int i = 0; i < ids_list.length; i++) {
			String[] _ids = ids_list[i].split(Prior.SPLIT);
			issueService.update_assignee(_ids, names_list[i]);
		}

		return ajax_info("OK");
	}

	/**
	 * 游客访问 反馈问题
	 *
	 * @param pkey  项目号
	 * @param model 页面MOdel
	 * @return 游客反馈问题页面
	 */
	@RequestMapping(value = "/visitor/{pkey}", method = RequestMethod.GET)
	public String vistor_issue(@PathVariable String pkey, Model model) {
		final Project project = projectService.fromKey(pkey);
		if (project == null) {
			// TODO 判断处理
		}
		model.addAttribute("project", project);
		model.addAttribute("types", typeService.all_types());
		return "issue/visitor";
	}

	/**
	 * 查看问题画面
	 *
	 * @param issue_key 问题KEY
	 * @param model     UI 模型
	 * @return 问题显示画面
	 */
	@RequestMapping(value = "/view/{issue_key}")
	public String issue_view(@PathVariable String issue_key, Model model) {
		final IssueInformation issue = issueService.from_key(issue_key);
		model.addAttribute("info", issue);
		List<Priopity> priopity_list = priopityService.priopity();
		model.addAttribute("priopities", priopity_list);
		model.addAttribute("labels", labelService.all_labels());
		return "issue/view";
	}

	/**
	 * 查看问题的回复信息，分页获取
	 *
	 * @param criteria 分页信息
	 * @param issue_id 问题号
	 * @return 问题显示画面
	 */
	@RequestMapping(value = "/view/comments/{issue_id}", method = RequestMethod.GET)
	@ResponseBody
	public PaginationResult<CommentAction> issue_view_comments(
			@PaginationParam(required = false) PaginationCriteria criteria,
			@PathVariable long issue_id) {

		return commentService
				.page_commentaction_by_issuekey(issue_id, criteria);

	}

	/**
	 * 关闭时批量回复信息
	 *
	 * @param ids     问题id列表 表示 要回复哪些信息
	 * @param content 详细回复内容
	 * @return ajax_info ajax提示信息
	 */
	@RequestMapping(value = "/close_comment_submit")
	@ResponseBody
	public AjaxMessage close_comment(String ids, String content) {
		String[] id_list = ids.split(",");
		Comment comment = new Comment();
		comment.setContent(content);
		ShiroDbRealm.ShiroUser shiroUser = (ShiroDbRealm.ShiroUser) SecurityUtils
				.getSubject().getPrincipal();
		comment.setUid(shiroUser.getId());
		comment.setUname(shiroUser.getName());
        issueService.close_open_issue(id_list, Macro.CLOSE);
		commentService.add_comments(comment, id_list);
		return ajax_info("关闭成功");
	}

	/** 修复问题时使用。如果content存在为 回复修复，不存在为 直接修复 （不需要回复） */
	@RequestMapping(value = "/fix_comment_submit")
	@ResponseBody
	public AjaxMessage fix_comment(
			@RequestParam(value = "id", required = true) String id,
			@RequestParam(value = "content", required = false) String content) {
		Comment comment = new Comment();
		comment.setContent(content);
		ShiroDbRealm.ShiroUser shiroUser = (ShiroDbRealm.ShiroUser) SecurityUtils
				.getSubject().getPrincipal();
		comment.setUid(shiroUser.getId());
		comment.setUname(shiroUser.getName());
		// if(!StringUtils.equals(content,null)){
		// logger.info("not content");
		commentService.add_comment(comment, Long.parseLong(id));
		// }
		String[] ids = id.split(Prior.SEPARATE);
		issueService.set_issue_fixed(ids);
		return ajax_info("问题修复成功");
	}

	/**
	 * 直接反馈问题，不需要通过登录的方式的保存操作
	 *
	 * @param issue  反馈信息
	 * @param result 验证信息
	 * @return 反馈问题
	 */
	@RequestMapping(value = "/visitor/save", method = RequestMethod.POST)
	@ResponseBody
	public AjaxMessage vistor_save(
			@Valid Issue issue,
			BindingResult result,
			@RequestParam(value = "attachment", required = false) List<MultipartFile> attachments) {
		if (result.hasErrors()) {
			return ajax_error("该项目不存在", result.getAllErrors());
		}
		if (attachments != null && !attachments.isEmpty()) {
			// 附件UUID名称
			String[] file_name = new String[attachments.size()];
			String file_uuid;
			Attachment attachment;
			final List<Attachment> attachment_domains = Lists.newArrayList();
			for (int i = 0; i < attachments.size(); i++) {
				file_uuid = UUID.randomUUID().toString();
				file_name[i] = file_uuid;
				try {
					attachmentService.add_attachment(file_uuid, attachments
							.get(i).getBytes());
				} catch (IOException e) {
					logger.error("文件上传保存时发生错误!", e);
				}
				attachment = new Attachment();
				attachment.setUrl("/action/attach/" + file_name[i]);
				attachment.setName(attachments.get(i).getOriginalFilename());
				attachment_domains.add(attachment);
			}
			issue.setSummary(issue.getSummary().trim());
			issueService.create_project_issue_attachments(issue,
					attachment_domains);
		} else {
			issueService.create_project_issue(issue, issue.getPid());
		}
		return ajax_info("反馈问题成功，感谢你反馈的问题");
	}

	/**
	 * 根据ID获取回复信息
	 *
	 * @param id 回复ID
	 * @return 回复信息
	 */
	@RequestMapping(value = "/comment/{id}", method = RequestMethod.GET)
	@ResponseBody
	public Comment issue_comment(@PathVariable long id) {
		return commentService.comment_with_id(id);
	}

	/**
	 * 关闭一个或者多个反馈问题
	 *
	 * @param ids 关闭问题ID，一个或者多个
	 * @return 是否成功
	 */
	@RequestMapping(value = "close", method = RequestMethod.POST)
	@ResponseBody
	public AjaxMessage delete(String ids) {
		String[] id_array = ids.split(Prior.SEPARATE);
		issueService.close_open_issue(id_array, Macro.CLOSE);
		return ajax_info("成功");
	}

	/**
	 * 重新打开问题
	 * <p>
	 * Fixed:<a
	 * href="http://192.168.83.214:18080/cdms/issue/view/cdms-56">cdms-56
	 * </a>,由于代码被注释掉
	 * </p>
	 *
	 * @param id 问题ID
	 * @return ajax提示信息
	 */
	@RequestMapping(value = "reopen/{id}", method = RequestMethod.GET)
	@ResponseBody
	public AjaxMessage reopen(@PathVariable String id) {
		String[] ids = id.split(Prior.SEPARATE);
		issueService.close_open_issue(ids, Macro.OPEN);
		return ajax_info("重新打开成功");
	}

	/**
	 * 更改一个或者多个问题标签
	 *
	 * @param ids 更改问题标签，一个或者多个
	 * @return 是否成功
	 */
	@RequestMapping(value = "label_change", method = RequestMethod.POST)
	@ResponseBody
	public AjaxMessage label_change(String ids, int lv) {
		String[] id_array = ids.split(Prior.SEPARATE);
		issueService.update_issue_label(id_array, lv);
		return ajax_info("成功");
	}

	/**
	 * Update the issues' priopity
	 *
	 * @param ids      list of ids string spilt by Prior.SEPARATE
	 * @param priopity int value :the priopity you want to set
	 * @return ajx_msg
	 */
	@RequestMapping(value = "priopity_change", method = RequestMethod.POST)
	@ResponseBody
	public AjaxMessage priopity_change(String ids, int priopity) {
		try {
			String[] ids_string = ids.split(Prior.SEPARATE);
			issueService.set_priopity(ids_string, priopity);
			return ajax_info("success");
		} catch (Exception e) {
			return ajax_info("failed");
		}
	}

	/**
	 * 获取所有项目的id和name，并作为commbo对象返回给commbo使用。
	 *
	 * @return 项目Commbo
	 */
	@RequestMapping("all")
	@ResponseBody
	public List<CommboValue> project_commbo() {
		List<Project> projects = projectService.all_projects();
		List<CommboValue> commboValues = Lists.newArrayList();
		for (Project project : projects) {
			CommboValue commboValue = new CommboValue();
			mapper.map(project, commboValue);
			commboValues.add(commboValue);
		}
		return commboValues;
	}

	/**
	 * 获取所有项目的id和name，并作为commbo对象返回给commbo使用。
	 *
	 * @return 项目Commbo
	 */
	@RequestMapping("new_issue_p_select")
	@ResponseBody
	public List<CommboValue> new_issue_p_select() {
		List<Project> projects = projectService.all_projects();
		List<CommboValue> commboValues = Lists.newArrayList();
		for (Project project : projects) {
			CommboValue commboValue = new CommboValue();
			mapper.map(project, commboValue);

			commboValue.setText(project.getCode() + "  "
					+ commboValue.getText());
			commboValues.add(commboValue);
		}
		return commboValues;
	}

	/**
	 * 回复问题
	 *
	 * @param comment 回复内容
	 * @return ajax提示信息
	 */
	@RequestMapping(value = "/comment")
	@ResponseBody
	public AjaxMessage comment_issue(@Valid Comment comment,
									 BindingResult result) {
		if (result.hasErrors()) {
			return ajax_error("验证无法通过", result.getAllErrors());
		}
		ShiroDbRealm.ShiroUser shiroUser = (ShiroDbRealm.ShiroUser) SecurityUtils
				.getSubject().getPrincipal();
		comment.setUid(shiroUser.getId());
		comment.setUname(shiroUser.getName());
		commentService.add_comment(comment, comment.getIssue());
		Map<String, Object> infoMap = Maps.newHashMap();
		infoMap.put("update",
				Dates.dateToString(comment.getCreated(), 4));
		return ajax_info("回复成功", infoMap);
	}

	@RequestMapping(value = "/load", method = RequestMethod.GET)
	@ResponseBody
	public List<Project> getProject(String q) {
		return projectService.fuzzySearchProjects(q);
	}

	/**
	 * 反馈问题，不需要通过登录的方式的保存操作
	 *
	 * @param issue  反馈信息
	 * @param result 验证信息
	 * @return ajax_info 反馈问题
	 */
	@RequestMapping(value = "save", method = RequestMethod.POST)
	@ResponseBody
	public AjaxMessage add_que(
			@Valid Issue issue,
			BindingResult result,
			@RequestParam(value = "attachment", required = false) List<MultipartFile> attachments) {
		String str = issue.getSummary();
		str = str.replace("<", "&lt");
		str = str.replace(">", "&gt");
		issue.setSummary(str);
		if (result.hasErrors()) {
			return ajax_error("该项目不存在", result.getAllErrors());
		}
		// 设置登录人信息
		ShiroDbRealm.ShiroUser shiroUser = (ShiroDbRealm.ShiroUser) SecurityUtils
				.getSubject().getPrincipal();
		// 设置报告人登录信息
		issue.setReporter(shiroUser.getName());
		issue.setReporterLogin(shiroUser.getLogin());
		issue.setReporterMail(shiroUser.getEmail());

		if (attachments != null && !attachments.isEmpty()) {
			// 附件UUID名称
			String[] file_name = new String[attachments.size()];
			String file_uuid;
			Attachment attachment;
			final List<Attachment> attachment_domains = Lists.newArrayList();
			for (int i = 0; i < attachments.size(); i++) {
				file_uuid = UUID.randomUUID().toString();
				file_name[i] = file_uuid;
				try {
					attachmentService.add_attachment(file_uuid, attachments
							.get(i).getBytes());
				} catch (IOException e) {
					logger.error("文件上传保存时发生错误!", e);
				}
				attachment = new Attachment();
				attachment.setUrl("/action/attach/" + file_name[i]);
				attachment.setName(attachments.get(i).getOriginalFilename());
				attachment_domains.add(attachment);
			}
			issue.setSummary(issue.getSummary().trim());
			logger.info(attachment_domains.size());
			issueService.create_project_issue_attachments(issue,
					attachment_domains);
		} else {
			issueService.create_project_issue(issue, issue.getPid());
		}
		return ajax_info("反馈问题成功，感谢你反馈的问题");
	}

	/**
	 * 根据知道的project 得到其所有的问题类型的数量统计
	 *
	 * @param projectId 项目id
	 * @return list类型的数量
	 */
	@RequestMapping(value = "issue_counts/{pid}", method = RequestMethod.GET)
	@ResponseBody
	public List<Integer> issue_counts(@PathVariable("pid") long projectId) {
		return issueService.count_with_project_status_type(projectId);
	}

}
